package com.appleeducate.fluttermidi;

import cn.sherlock.com.sun.media.sound.SF2Soundbank;
import cn.sherlock.com.sun.media.sound.SoftSynthesizer;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

import java.io.File;
import java.io.IOException;

import jp.kshoji.javax.sound.midi.InvalidMidiDataException;
import jp.kshoji.javax.sound.midi.MidiUnavailableException;
import jp.kshoji.javax.sound.midi.Receiver;
import jp.kshoji.javax.sound.midi.ShortMessage;

import com.joymido.midi.MidiDriver;

/**
 * FlutterMidiPlugin
 */
public class FlutterMidiPlugin implements MethodCallHandler {
    private SoftSynthesizer synth;
    private Receiver recv;

    private SoftSynthesizer synth_b;
    private Receiver recv_b;

    private MidiDriver mDriver;

    /**
     * Plugin registration.
     */
    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_midi");
        channel.setMethodCallHandler(new FlutterMidiPlugin());
    }

    private void prepareBeats(String _path) {
        try {
            File _file = new File(_path);
            SF2Soundbank sf = new SF2Soundbank(_file);
            synth_b = new SoftSynthesizer();
            synth_b.open();
            synth_b.loadAllInstruments(sf);
            synth_b.getChannels()[0].programChange(0);
            synth_b.getChannels()[1].programChange(1);
            recv_b = synth_b.getReceiver();
        }catch (Throwable e){
            e.printStackTrace();
        }
    }

    @Override
    public void onMethodCall(MethodCall call, Result result) {
        if(android.os.Build.VERSION.SDK_INT <23){
            onMethodCallX(call, result);
            return;
        }
        String _isBeats = call.argument("isBeats");
        if (call.method.equals("prepare_midi")) {
            try {
                String _path = call.argument("path");
//                if ("1".equals(_isBeats)) {
//                    prepareBeats(_path);
//                    return;
//                }
//                File _file = new File(_path);
//                SF2Soundbank sf = new SF2Soundbank(_file);
//                synth = new SoftSynthesizer();
//                synth.open();
//                synth.loadAllInstruments(sf);
//                synth.getChannels()[0].programChange(0);
//                synth.getChannels()[1].programChange(1);
//                recv = synth.getReceiver();
//
                mDriver = new MidiDriver();
                mDriver.initSF(_path);

            } catch (Exception e) {
                e.printStackTrace();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("change_sound")) {
            try {
                String _path = call.argument("path");
                File _file = new File(_path);
                SF2Soundbank sf = new SF2Soundbank(_file);
                synth = new SoftSynthesizer();
                synth.open();
                synth.loadAllInstruments(sf);
                synth.getChannels()[0].programChange(0);
                synth.getChannels()[1].programChange(1);
                recv = synth.getReceiver();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (MidiUnavailableException e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("play_midi_note")) {
            int _note = call.argument("note");
            int vol = call.argument("vol");
            try {
                // ShortMessage msg = new ShortMessage();
                // msg.setMessage(ShortMessage.NOTE_ON, 1, _note, 127);
                // if ("1".equals(_isBeats)) {
                //     recv_b.send(msg, -1);
                // } else {
                //     recv.send(msg, -1);
                // }

                mDriver.play(_note,vol);

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("stop_midi_note")) {
            int _note = call.argument("note");
            try {
                // ShortMessage msg = new ShortMessage();
                // msg.setMessage(ShortMessage.NOTE_OFF, 0, _note, 127);

                // if ("1".equals(_isBeats)) {
                //     recv_b.send(msg, -1);
                // } else {
                //     recv.send(msg, -1);
                // }
                mDriver.stop(_note);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
        }
    }






    public void onMethodCallX(MethodCall call, Result result) {
        String _isBeats = call.argument("isBeats");
        if (call.method.equals("prepare_midi")) {
            try {
                String _path = call.argument("path");
                if ("1".equals(_isBeats)) {
                    prepareBeats(_path);
                    return;
                }
                File _file = new File(_path);
                SF2Soundbank sf = new SF2Soundbank(_file);
                synth = new SoftSynthesizer();
                synth.open();
                synth.loadAllInstruments(sf);
                synth.getChannels()[0].programChange(0);
                synth.getChannels()[1].programChange(1);
                recv = synth.getReceiver();
//
//                mDriver = new MidiDriver();
//                mDriver.initSF(_path);

            } catch (Exception e) {
                e.printStackTrace();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("change_sound")) {
            try {
                String _path = call.argument("path");
                File _file = new File(_path);
                SF2Soundbank sf = new SF2Soundbank(_file);
                synth = new SoftSynthesizer();
                synth.open();
                synth.loadAllInstruments(sf);
                synth.getChannels()[0].programChange(0);
                synth.getChannels()[1].programChange(1);
                recv = synth.getReceiver();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (MidiUnavailableException e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("play_midi_note")) {
            int _note = call.argument("note");
            try {
                 ShortMessage msg = new ShortMessage();
                 msg.setMessage(ShortMessage.NOTE_ON, 1, _note, 127);
                 if ("1".equals(_isBeats)) {
                     recv_b.send(msg, -1);
                 } else {
                     recv.send(msg, -1);
                 }

//                mDriver.play(_note);

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (call.method.equals("stop_midi_note")) {
            int _note = call.argument("note");
            try {
                 ShortMessage msg = new ShortMessage();
                 msg.setMessage(ShortMessage.NOTE_OFF, 0, _note, 127);

                 if ("1".equals(_isBeats)) {
                     recv_b.send(msg, -1);
                 } else {
                     recv.send(msg, -1);
                 }
//                mDriver.stop(_note);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
        }
    }



}
